#include "graphicsimageitem.h"
#include <cv.h>
#include <highgui.h>
#include <QString>
#include <QPainter>
#include <unistd.h>


GraphicsImageItem::GraphicsImageItem(QString *rawFile, int width, int height, QGraphicsObject *parent) :
        QGraphicsObject(parent), BLOCKSIZE(width*height*PFCMU::CAMS), TIMESTAMPINC(width==640?4:1)
{
    m_File = new QString(*rawFile);
    QStringList pathList = m_File->split("/", QString::SkipEmptyParts);
    title = new QString(pathList.at(pathList.count()-1));

    m_ImageWidth = width;
    m_ImageHeight = height;
    m_Width = m_ImageWidth + EDGEWIDTH + EDGEWIDTH;
    m_Height = m_ImageHeight + EDGEHEIGHT + EDGEWIDTH;

    raw.open(m_File->toLatin1().data(), m_ImageWidth, m_ImageHeight);
    m_FrameCount = PFCMU::RAWFile::framecount(m_File->toLatin1().data(), BLOCKSIZE);
    //std::cout << m_FrameCount << std::endl;
    //if(m_FrameCount>250)
        //m_FrameCount = 250;
    m_MinTimeStamp = getTimeStamp(raw, 0);
    m_MaxTimeStamp = getTimeStamp(raw, m_FrameCount-1);
    m_CurrentTimeStamp = m_MinTimeStamp;
    m_CurrentCam = 0;

    IplImage *bayer = cvCreateImage(cvSize(m_ImageWidth,m_ImageHeight), IPL_DEPTH_8U, 1);
    IplImage *rgb = cvCreateImage(cvSize(m_ImageWidth,m_ImageHeight), IPL_DEPTH_8U, 3);
    cvZero(bayer);
    cvZero(rgb);
    PFCMU::RAWFile::const_iterator itr = raw.at(0);
    itr.extract(m_CurrentCam, bayer);
    cvCvtColor(bayer, rgb, CV_BayerGR2RGB);
    imageData = new IplQImage(rgb, 3);
    cvReleaseImage(&bayer);
    cvReleaseImage(&rgb);
}

QRectF GraphicsImageItem::boundingRect() const
{
    return QRectF(0,0,m_Width,m_Height);
}

QPainterPath GraphicsImageItem::shape() const
{
    QPainterPath path;
    path.addRect(0,0,m_Width, m_Height);
    return path;
}

void GraphicsImageItem::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget)
{
    Q_UNUSED(widget);
    if(imageData != NULL)
    {
        QImage *qImg = imageData->getQImage();
        painter->drawImage(EDGEWIDTH, EDGEHEIGHT, *qImg);
        painter->drawText(EDGEWIDTH, EDGEHEIGHT, *title);
        painter->drawText(EDGEWIDTH,m_Height,tr("%1").arg(m_CurrentTimeStamp));
    }
}

void GraphicsImageItem::mouseDoubleClickEvent(QGraphicsSceneMouseEvent *event)
{
    QGraphicsItem::mouseDoubleClickEvent(event);
    this->update(0,0,m_Width,m_Height);
    emit switchToSingle(m_File);
}

int GraphicsImageItem::getWidth() const
{
    return m_Width;
}

int GraphicsImageItem::getHeight() const
{
    return m_Height;
}

PFCMU::timestamp_t GraphicsImageItem::getCurrentTimeStamp() const
{
    return m_CurrentTimeStamp;
}

QString GraphicsImageItem::getName() const
{
    return *title;
}

void GraphicsImageItem::saveQImage(QString fileName) const
{
    QImage *img = imageData->getQImage();
    img->save(fileName);
}

void GraphicsImageItem::setCurrentTimeStamp(PFCMU::timestamp_t timeStamp)
{
    m_CurrentTimeStamp = timeStamp;
    this->update(0,EDGEHEIGHT+m_ImageHeight, m_Width, EDGEHEIGHT);
}

PFCMU::timestamp_t GraphicsImageItem::getMinTimeStamp() const
{
    return m_MinTimeStamp;
}

void GraphicsImageItem::onInitTimeStamp(PFCMU::timestamp_t value)
{
    this->setCurrentTimeStamp(value);
}

void GraphicsImageItem::onTimeStampUpdated(PFCMU::timestamp_t value)
{
    //TODO
    setCurrentTimeStamp(value);
    off64_t targetFrame = searchFrame(value);
    CvFont font;
    cvInitFont(&font, CV_FONT_HERSHEY_SIMPLEX,1,1,0,1,CV_AA);
    if(targetFrame < 0)
    {
        //blank image
        IplImage *rgb = cvCreateImage(cvSize(m_ImageWidth,m_ImageHeight), IPL_DEPTH_8U, 3);
        cvZero(rgb);
        cvPutText(rgb, "BLANK", cvPoint(50,50), &font, CV_RGB(255,255,255));
    }
    else if(targetFrame < m_FrameCount)
    {
        IplImage *bayer = cvCreateImage(cvSize(m_ImageWidth,m_ImageHeight), IPL_DEPTH_8U, 1);
        IplImage *rgb = cvCreateImage(cvSize(m_ImageWidth,m_ImageHeight), IPL_DEPTH_8U, 3);
        cvZero(bayer);
        cvZero(rgb);
        PFCMU::RAWFile::const_iterator itr = raw.at(targetFrame);
        itr.extract(m_CurrentCam, bayer);
        cvCvtColor(bayer, rgb, CV_BayerGR2RGB);
        //update image
        imageData->updateImage(rgb);
        cvReleaseImage(&bayer);
        cvReleaseImage(&rgb);
    }
    this->update(0,0,m_Width,EDGEHEIGHT+m_ImageHeight);
}

void GraphicsImageItem::onCamUpdated(int value)
{
    m_CurrentCam = value;
    off64_t targetFrame = searchFrame(m_CurrentTimeStamp);
    CvFont font;
    cvInitFont(&font, CV_FONT_HERSHEY_SIMPLEX,1,1,0,1,CV_AA);
    if(targetFrame < 0)
    {
        //blank image
        IplImage *rgb = cvCreateImage(cvSize(m_ImageWidth,m_ImageHeight), IPL_DEPTH_8U, 3);
        cvZero(rgb);
        cvPutText(rgb, "BLANK", cvPoint(50,50), &font, CV_RGB(255,255,255));
    }
    else if(targetFrame < m_FrameCount)
    {
        IplImage *bayer = cvCreateImage(cvSize(m_ImageWidth,m_ImageHeight), IPL_DEPTH_8U, 1);
        IplImage *rgb = cvCreateImage(cvSize(m_ImageWidth,m_ImageHeight), IPL_DEPTH_8U, 3);
        cvZero(bayer);
        cvZero(rgb);
        PFCMU::RAWFile::const_iterator itr = raw.at(targetFrame);
        itr.extract(m_CurrentCam, bayer);
        cvCvtColor(bayer, rgb, CV_BayerGR2RGB);
        //update image
        imageData->updateImage(rgb);
        cvReleaseImage(&bayer);
        cvReleaseImage(&rgb);
    }
    this->update(0,0,m_Width,EDGEHEIGHT+m_ImageHeight);
}

void GraphicsImageItem::onPlayTimeStampUpdated(PFCMU::timestamp_t value)
{
    this->onTimeStampUpdated(value);
    //sleep(1);
    qDebug(tr("%1").arg(value).toAscii());
    emit oneFrameFinished();
}

PFCMU::timestamp_t GraphicsImageItem::getMaxTimeStamp() const
{
    return m_MaxTimeStamp;
}

PFCMU::timestamp_t GraphicsImageItem::getTimeStamp(PFCMU::RAWFile &m_Raw, off64_t m_FrameNumber) const
{
    IplImage *m_Bayer = cvCreateImage(cvSize(m_ImageWidth,m_ImageHeight), IPL_DEPTH_8U, 1);
    PFCMU::RAWFile::const_iterator itr = m_Raw.at(m_FrameNumber);
    itr.extract(0, m_Bayer);
    PFCMU::timestamp_t ts = PFCMU::get_timestamp(m_Bayer->imageData);
    cvReleaseImage(&m_Bayer);

    return ts;
}

off64_t GraphicsImageItem::searchFrame(PFCMU::timestamp_t targetTimeStamp)
{
    off64_t result = -1;

    off64_t currFrame;
    off64_t preFrame;
    off64_t tempFrame;

    currFrame = 0;
    if(m_MinTimeStamp == targetTimeStamp)
    {
        result = currFrame;
    }
    else
    {
        preFrame = currFrame;
        currFrame = m_FrameCount - 1;

        //start search
        PFCMU::timestamp_t currTS = getTimeStamp(raw, currFrame);
        for(;;)
        {
            if(currTS == targetTimeStamp)
            {
                //frame found
                result = currFrame;
                break;
            }
            else
            {
                //test blank frame
                //if the frame we want is dropped, that is a blank frame
                off64_t offsetFrame = (currTS - targetTimeStamp)/4;
                tempFrame = currFrame - offsetFrame;
                if(tempFrame == preFrame || tempFrame < 0)
                {
                    result = -1;
                    break;
                }
                else
                {
                    //continue search
                    preFrame = currFrame;
                    currFrame = tempFrame;
                }
            }
            currTS = getTimeStamp(raw, currFrame);
        }
    }
    return result;
}
